﻿using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml.Linq;
using Microsoft.SharePoint;

namespace SP14.ExternalList
{
    public class HttpHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            if (context.Request.QueryString["XML"] == "1")
            {
                MakeXML(context);
                return;
            }
            if (context.Request.QueryString["IQY"] == "1")
            {
                MakeIQY(context);
                return;
            }
        }

        static void MakeXML(HttpContext context)
        {
            if (String.IsNullOrEmpty(context.Request.QueryString["List"]))
            {
                throw new ArgumentNullException("List");
            }
            if (String.IsNullOrEmpty(context.Request.QueryString["View"]))
            {
                throw new ArgumentNullException("View");
            }
            var list = SPContext.Current.Web.Lists[new Guid(context.Request.QueryString["List"])];
            var view = list.Views[new Guid(context.Request.QueryString["View"])];
            var rs = list.GetItems(view);
            string xml = rs.Xml;
            int index = xml.LastIndexOf("</s:ElementType>");

            if (index > 0)
            {
                xml = xml.Insert(index, GetSchemaXml(view, rs.XmlDataSchema));
            }
            context.Response.ContentType = "text/xml";
            context.Response.Write(xml);
        }

        static void MakeIQY(HttpContext context)
        {
            if (String.IsNullOrEmpty(context.Request.QueryString["List"]))
            {
                throw new ArgumentNullException("List");
            }
            if (String.IsNullOrEmpty(context.Request.QueryString["View"]))
            {
                throw new ArgumentNullException("View");
            }
            
            StringBuilder qb = new StringBuilder();
            qb.Append("WEB");
            qb.AppendLine();
            qb.Append("1");
            qb.AppendLine();
            qb.AppendFormat("{0}/_vti_bin/ExternalList/owssvr.dll?XML=1&List={1}&View={2}", SPContext.Current.Web.Url, context.Request.QueryString["List"], context.Request.QueryString["View"]);
            qb.AppendLine();
            qb.AppendLine();
            qb.AppendFormat("Selection={0}-{1}", context.Request.QueryString["List"], context.Request.QueryString["View"]);
            qb.AppendLine();
            qb.Append("EditWebPage=");
            qb.AppendLine();
            qb.Append("Formatting=None");
            qb.AppendLine();
            qb.Append("PreFormattedTextToColumns=True");
            qb.AppendLine();
            qb.Append("ConsecutiveDelimitersAsOne=True");
            qb.AppendLine();
            qb.Append("SingleBlockTextImport=False");
            qb.AppendLine();
            qb.Append("DisableDateRecognition=False");
            qb.AppendLine();
            qb.Append("DisableRedirections=False");
            qb.AppendLine();
            qb.AppendFormat("SharePointApplication={0}/_vti_bin/ExternalList", SPContext.Current.Web.Url);
            qb.AppendLine();
            qb.AppendFormat("SharePointListView={0}", context.Request.QueryString["View"]);
            qb.AppendLine();
            qb.AppendFormat("SharePointListName={0}", context.Request.QueryString["List"]);
            qb.AppendLine();
            qb.Append("RootFolder=");

            context.Response.ContentType = "text/x-ms-iqy";
            context.Response.AppendHeader("Content-Disposition", "attachment; filename=owssvr.iqy");
            using (StreamWriter sw = new StreamWriter(context.Response.OutputStream, Encoding.UTF8))
            {
                sw.Write(qb.ToString());
            }
        }

        static string GetSchemaXml(SPView view, string dataSchema)
        {
            XNamespace s = "uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882";
            XNamespace dt = "uuid:C2F41010-65B3-11d1-A29F-00AA00C14882";
            XNamespace rs = "urn:schemas-microsoft-com:rowset";

            XElement schemaXml = XElement.Parse(dataSchema);

            int count = schemaXml.Descendants(s + "AttributeType").Count();

            string typeName = string.Empty;
            long maxLength = 0;
            StringBuilder sb = new StringBuilder();

            foreach (string name in view.ViewFields)
            {
                SPField f = view.ParentList.Fields.GetField(name);
                if (schemaXml.Descendants(s + "AttributeType").Where(e => (string)e.Attribute(rs + "name") == f.Title).Count() == 0
                    && ParseFieldType(f.Type, ref typeName, ref maxLength))
                {
                    sb.AppendFormat("\t<s:AttributeType rs:name=\"{0}\" name=\"ows_{1}\" rs:number=\"{2}\">", f.Title, f.StaticName, ++count);
                    sb.AppendLine();
                    sb.AppendFormat("\t\t<s:datatype dt:type=\"{0}\" dt:maxLength=\"{1}\"/>", typeName, maxLength);
                    sb.AppendLine();
                    sb.AppendLine("\t</s:AttributeType>");
                }
            }

            return sb.ToString();
        }

        static bool ParseFieldType(SPFieldType type, ref string name, ref long maxLength)
        {
            switch (type)
            {
                case SPFieldType.Boolean:
                    name = "boolean";
                    maxLength = 1;
                    break;

                case SPFieldType.Choice:
                    name = "string";
                    maxLength = 512;
                    break;

                case SPFieldType.Currency:
                    name = "float";
                    maxLength = 8;
                    break;

                case SPFieldType.DateTime:
                    name = "datetime";
                    maxLength = 8;
                    break;

                case SPFieldType.Guid:
                    name = "string";
                    maxLength = 38;
                    break;

                case SPFieldType.Integer:
                    name = "int";
                    maxLength = 8;
                    break;

                case SPFieldType.Lookup:
                    name = "string";
                    maxLength = 512;
                    break;

                case SPFieldType.Note:
                    name = "string";
                    maxLength = 1073741823;
                    break;

                case SPFieldType.Number:
                    name = "float";
                    maxLength = 8;
                    break;

                case SPFieldType.Text:
                    name = "string";
                    maxLength = 512;
                    break;

                case SPFieldType.User:
                    name = "string";
                    maxLength = 512;
                    break;

                default:
                    return false;
            }
            return true;
        }
    }
}
